Zagadnienia teoretyczne

Wyjaśnić pojęcie ratingów, jakie poziomy ratingów stosują najbardziej znane agencje ratingowe?

Istotą ratingów jest ustalenie jakości obligacji wystawianych przez duże przedsiębiorstwa / kraje. Ratingi ustalają agencje ratingowe (np. Moody’s, Fitchi Standard&Poors). Są one obiektywnym i stabilnym źródłem informacji o poziomie ryzyka związanego z inwestycją. S&P oraz Fitch mają system taki, że najwyższym ratingiem możliwym do uzyskania jest AAA, następnie jest AA, A, BBB, BB, B, CCC, CC, C oraz D, czyli bankructwo. Z kolei Moody’s stosuje system taki, że najwyższą oceną jest Aaa, potem Aa2, A2, Baa2, Ba2, B2, Caa2, Ca oraz C, gdzie C oznacza bankructwo.
Od oceny AAA do BBB można wyróżnić obligacje o standardzie inwestycyjnym. Wiążą się one małym prawodopodobieństwem niewypłacalności. Skutkuje to tym, że występuje przy tym niska stopa zwrotu. Z drugiej strony, od oceny BB do C, są to obligacje śmieciowe charakteryzujące się wysokim oprocentowaniem i wysokim ryzykiem.

Wyjaśnić ideę modelu CreditMetrics. Na czym on bazuje i w jaki sposób opisuje ryzyko kredytowe?

Model CreditMetrics opiera się na koncepcji Value at Risk (VaR), która określa maksymalną oczekiwaną stratę z określonym prawdopodobieństwem oraz ustalonym horyzontem czasowym. W przypadku ryzyka kredytowego, zazwyczaj stosuje się roczny horyzont czasowy i ufność na poziomie 99.9%. Stosujemy metodę CreditMetrics, ponieważ precyzyjnie opisuje ona ryzyko kredytowe poprzez uwzględnienie zmian w wiarygodności kredytowej. Strata (lub zysk) wynika ze zmiany ratingu danego przedsiębiorstwa/państwa. Gdy rating spadnie, wartość naszej obligacji również spada. Do obliczeniu VaR i ES dla portfela składającego się z kilku firm, losujemy wartości z wielowymiarowego rozkładu normalnego o zadanej macierzy korelacji. Następnie dla macierzy przejścia sprawdza się dla każdej obligacji, jak liczba losowa wpływa na przyszły rating obligacji. Jest to na podstawie rozkładu N(0,1). Dzięki tej metodzie, można wygenerować określoną liczbę scenariuszy określających z jakim ratingiem skończą firmy z portfela za rok. Następnie wycenia się każdą z obligacji na koniec roku i wyznacza wartość portfela. Potem porządkuję od wartości najmniejszych do największych i znajduję odpowiedni kwantyl dla wartości portfela. VaR obliczam odejmując wartość wyznaczoną od wartości portfela, gdyby rating się nie zmienił. ES obliczam odejmując średnią z “wyciętych” wartości od wartości porfela, gdyby rating się nie zmienił. Przy poziomie ufności 99.9%, wycinam najgorsze 0.01% możliwości.

Zadania praktyczne:

Stworzyłem funkcję, która liczy za mnie VaR oraz ES. Wybrałem obligacje, takie jak:
- 3-letnia obligacja o ratingu A (cena wykupu 100 000 zł, subordinated),
- 5-letnia obligacja o ratingu B (cena wykupu 50 000 zł, roczne kupony 5000 zł, senior secured),
- 2-letnia obligacja o ratingu CCC (cena wykupu 50 000 zł, roczne kupony 10 000 zł, senior unsecured).

Założyłem takie współczynniki korelacji między inwestycjami: r12 = 0.2, r13 = 0.15, r23 = 0.4, ufność na poziomie 99.9%, liczbę scenariuszy o liczbie równej 30000.

library(mvtnorm)
library(dplyr)
library(stats)
library(DT)

#Funcja służąca przypisania do wylosowanej liczby danego ratingu. Operacja jest wykonywana dla każdej firmy. Argumentem funkcji jest ramka danych z wylosowanych liczb z wielowymiarowego rozkładu normalnego, ratingi początkowe oraz macierz przejścia.

matchranking <- function(losowanie, oceny, ratings){
  ramka <- data.frame(matrix(data = NA, nrow = nrow(losowanie), ncol = (length(oceny)*2)))
  
  for (i in 1:length(oceny)){
    letters <- c()
    ratingfun <- ratings[oceny[i],]
    dystr <- dystrybuanta(ratingfun)
    dystrkw <- kwant(dystr)
    
    for(a in 1:nrow(losowanie)){
      for(b in 1:ncol(dystrkw)){
        if((losowanie[a,i] >= dystrkw[5,b]) & (losowanie[a,i] < dystrkw[4,b])){
          letters <- c(letters, colnames(dystrkw)[b])
          break
        }
      }
    }
    
    ramka[,i] <- losowanie[,i]
    ramka[,length(oceny)+i] <- letters
  }
  return(ramka)
}

# Funkcja licząca dystrybuantę, jako argument przyjmuję wartości z macierzy przejścia (określony rząd)

dystrybuanta <- function(wartosci) {
  dol <- c(0)
  gora <- c(wartosci[,length(wartosci)])
   
  for(i in 2:(length(wartosci))){
    gora <- c(gora, gora[(i-1)] + wartosci[, (length(wartosci)-i+1)])
    dol <- c(dol, gora[i-1])
  }
  data <- t(data.frame(rev(as.vector(gora)),rev(as.vector(dol))))
  colnames(data) <- colnames(wartosci)
  rownames(data) <- c("Gora", "Dol")
  dyst <- rbind(wartosci, data)
  return(dyst)
}

#Funkcja obliczająca kwantyle rozkładu normalnegi dla danych wejściowych.
kwant <- function(dystr){
  dane <- as.data.frame(sapply(dystr[c(2,3),],qnorm, mean=0, sd=1))
  return(rbind(dystr,dane))
}
#Funkcja obliczająca wycenę dla wszystkich obligacji, argumentem jest ramka danych scenariuszy, stopy zwrotu, stopy odzysku, wektor lat, wartości ceny wykupu, wartości kuponów, typ obligacji oraz argument typu bool świadczący o tym, czy losuję wartość procentową ile dostanie pożyczkodawca gdyby firma zbankrutowała
wycena_wszystkich_obligacji <- function(scenarios, tab_proc, default_table, lata, wartosci, kupony, typ, los=F){
  scenarios <- scenarios[,((ncol(scenarios)/2)+1):ncol(scenarios)]
  for(i in 1:nrow(scenarios)){
    for(j in 1:(ncol(scenarios))){
      rating <- scenarios[i,j]
      if(rating=="Def"){
        scenarios[i,j] <- round(wycena_obligacji_bankrut(default_table, wartosci[j], typ = typ[j], los = los),2)
      } else{
        scenarios[i,j] <- round(wycena_jednej_obligacji(tab_proc, kupon = kupony[j], wartosc = wartosci[j], lata = lata[j], rating),2)
      }
    }
  }
  for(k in 1:ncol(scenarios)){
    scenarios[,k] <- as.numeric(scenarios[,k])
  }
  return(scenarios)
}

#Funkcja licząca wartość jednej obligacji. Argumenty: Stopy zwrotu, kupon, wartość ceny wykupu, lata, rating firmy
wycena_jednej_obligacji <- function(stzwrotu, kupon, wartosc, lata, rat){
  wart<- 0
  if(kupon!=0){
    wart<- kupon 
  }
  for(i in 1:(lata-1)){
    wart<- wart+ kupon/(1+(stzwrotu[rat,i]/100))^i
  }
  wart<- wart + wartosc/(1+(stzwrotu[rat, (lata-1)]/100))^(lata-1)
  return(wart)
}

#Funkcja licząca wartość jednej obligacji, gdy firma zbankrutuje. Argumenty: Stopy odzysku, wartość ceny wykupu, typ obligacji oraz czy losuję wartość, jaką pożyczkodawca dostanie spowrotem.
wycena_obligacji_bankrut <- function(default_tabelka, wartosc, typ, los = F){
  tab <- default_tabelka[typ,]
  if(los == F){
    return((tab[,1]/100)*wartosc)
  }
  procent <- rnorm(n=1,mean = tab[,1], sd=tab[,2])/100
  if(procent < 0){
    return(0)
  } else if (procent > 1){
    return(wartosc)
  } else{
    return(wartosc*procent)
  }
}

#Liczę wartość portfela na podstawie wycenionych obligacji. Argumentem jest ramka z wycenionymi obligacjami.
wartosc_portfela <- function(ramka){
  portfel <- rowSums(ramka)
  ramka <- cbind(ramka, portfel)
  return(ramka)
}

#Liczę VaR o podanej ufności dla ramki zawierającej wartości porfeli.
count_var <- function(ramka, kwantyl){
  ramka <- ramka %>% arrange(portfel)
  wartosci <- as.vector(ramka[,ncol(ramka)])
  return(as.numeric(quantile(wartosci, (1-kwantyl))))
}
#Liczę ES o podanej ufności dla ramki zawierającej wartości porfeli.
count_ES <- function(ramka, kwantyl){
  ramka <- ramka %>% arrange(portfel)
  wartosci <- as.vector(ramka[,ncol(ramka)])
  
  indeks_do_wycięcia <- length(wartosci) * (1-kwantyl)
  wyc_wartosci <- wartosci[1:indeks_do_wycięcia]
  return(mean(wyc_wartosci))
}

#Szukam wartości portfela gdyby ratingi się nie zmieniły. Argumenty: scenariusze, ratingi początkowe, wartości portfeli.
znajdz_wycene_aktualna <- function(dataframe, ratingi, portfele){
  dataframe <- dataframe[, (ncol(dataframe)-length(ratingi)+1):ncol(dataframe)]
  
  for (i in 1:nrow(dataframe)) {
    if (all(dataframe[i, ] == ratingi)) {
      wycena <- portfele[i, ncol(portfele)]
      return(wycena)
    }
  }
  return(0)
}

#Główna funkcja licząca VaR i ES. Argumenty: współczynniki korelacji, liczba scenariuszy, ratingi początkowe, macierz przejścia, stopy zwrotu, stopy odzysku, wektory lat, cen wykupu, kuponów, typów obligacji, ufność oraz czy losuję wartość ze stopy odzysku w przypadku bankructwa firmy.
credit_metrics <- function(korelacje, scenariusze, ratingi_poczatkowe, dataratings,
                           data_stopy_zwrotu,
                           data_stopy_odzysku,
                           lata,
                           cena_wykupu,
                           kupony,
                           typ,
                           kwantyl,
                           los=F){
  losowanie <- rmvnorm(scenariusze, mean = rep(0,nrow(korelacje)), sigma = korelacje)
  
  scen <- matchranking(losowanie, ratingi_poczatkowe, dataratings)
  
  wycena <- wycena_wszystkich_obligacji(scen,
                                        data_stopy_zwrotu,
                                        data_stopy_odzysku,
                                        lata,
                                        cena_wykupu,
                                        kupony,
                                        typ, 
                                        los=los)
  
  
  wyceny_portfeli <- wartosc_portfela(wycena)
  wycena_aktualnych_ratingow <- znajdz_wycene_aktualna(scen, ratingi_poczatkowe, wyceny_portfeli)
  
  VaR <- wycena_aktualnych_ratingow - count_var(wyceny_portfeli, kwantyl) 
  ES <- wycena_aktualnych_ratingow - count_ES(wyceny_portfeli, kwantyl) 
  
  return(list("Scenariusze" = scen, "Wycena" = wyceny_portfeli, "VaR" = VaR, "ES" = ES))
}

Zbadać, w jaki sposób zmieniłyby się wyniki, jeśli założylibyśmy, że inwestycje w portfelu nie są skorelowane. Jak uzyskane wyniki łączą się z pojęciem “dywersyfikacji ryzyka”.

Na początku liczę, jak wygląda sprawa dla przypadku, gdy nie losuję wartości procentowej ze stopy odzysku w razie bankructwa firmy. W tym przypadku pokażę również ramki danych z wygenerowanych scenariuszy, wycen oraz porównanie ES i VaR dla korelacji i bez.
stopy_zwrotu_df <- data.frame("Year 1" = c(3.60, 3.65, 3.72, 4.10, 5.55, 6.05, 15.05),
                                "Year 2" = c(4.17, 4.22, 4.32, 4.67, 6.02, 7.02, 15.02),
                                "Year 3" = c(4.73, 4.78, 4.93, 5.25, 6.78, 8.03, 14.03),
                                "Year 4" = c(5.12, 5.17, 5.32, 5.63, 7.27, 8.52, 13.52))

rownames(stopy_zwrotu_df) <- c("AAA", "AA", "A", "BBB", "BB", "B", "CCC")

stopy_odzysku_df <- data.frame(row.names = c("Senior Secured", "Senior Unsecured", "Senior Subordinated", "Subordinated", "Junior Subordninated"),
                                 "Mean %" = c(53.80, 51.13, 38.52, 32.74, 17.09),
                                 "Standard Deviation %" = c(26.86, 25.45, 23.81, 20.18, 10.90))

data_ratings_df <- read.csv2("Ratings.csv", row.names = 1)

korelacje <- matrix(c(1,0.2,0.15,
                      0.2,1,0.4,
                      0.15,0.4,1), nrow=3)

var_z_korelacja <- credit_metrics(korelacje = korelacje,
               scenariusze =  30000,
               ratingi_poczatkowe = c("A", "B", "CCC"),
               dataratings = data_ratings_df,
               data_stopy_zwrotu = stopy_zwrotu_df,
               data_stopy_odzysku = stopy_odzysku_df, 
               lata = c(3,5,2), 
               cena_wykupu = c(100000, 50000, 50000),
               kupony = c(0,5000,10000), 
               typ = c("Subordinated", "Senior Secured", "Senior Unsecured"), 
               kwantyl = 0.999,
               los=F)


korelacje <- matrix(c(1,0,0,
                      0,1,0,
                      0,0,1), nrow=3)

var_bez_korelacji<-credit_metrics(korelacje = korelacje,
               scenariusze =  30000,
               ratingi_poczatkowe = c("A", "B", "CCC"),
               dataratings = data_ratings_df,
               data_stopy_zwrotu = stopy_zwrotu_df,
               data_stopy_odzysku = stopy_odzysku_df, 
               lata = c(3,5,2), 
               cena_wykupu = c(100000, 50000, 50000),
               kupony = c(0,5000,10000), 
               typ = c("Subordinated", "Senior Secured", "Senior Unsecured"), 
               kwantyl = 0.999)
Tabelka z wygenerowanymi scenariuszami
datatable(var_bez_korelacji$Scenariusze)
Tabelka z wycenami portfeli
datatable(var_bez_korelacji$Wycena)
Tabelka z ES i VaR bez losowania stopy odzysku
VaRiES <- data.frame("VaR"=c(var_bez_korelacji$VaR, var_z_korelacja$VaR), "ES"=c(var_bez_korelacji$ES, var_z_korelacja$ES), row.names = c("Bez korelacji", "Z korelacjami"))
datatable(VaRiES)
Wniosek: VaR dla danych nieskorelowanych jest mniejszy, niż dla danych skorelowanych. To samo dotyczy ES. Aspekt ten wiąże się z dywersyfikacją ryzyka, ponieważ można wyciągnąć wniosek, że jeśli inwestor chce zmniejszyć ryzyko, to musi inwestować w obszary niepowiązane ze sobą. Jest wtedy mniejsza szansa, że jeśli jedna firma zbankrutuje, to druga razem z nią.
Tym razem losuję wartość procentową ze stopy odzysku:
var_z_korelacja_los <- credit_metrics(korelacje = korelacje,
               scenariusze =  30000,
               ratingi_poczatkowe = c("A", "B", "CCC"),
               dataratings = data_ratings_df,
               data_stopy_zwrotu = stopy_zwrotu_df,
               data_stopy_odzysku = stopy_odzysku_df, 
               lata = c(3,5,2), 
               cena_wykupu = c(100000, 50000, 50000),
               kupony = c(0,5000,10000), 
               typ = c("Subordinated", "Senior Secured", "Senior Unsecured"), 
               kwantyl = 0.999,
               los=T)


korelacje <- matrix(c(1,0,0,
                      0,1,0,
                      0,0,1), nrow=3)

var_bez_korelacji_los<-credit_metrics(korelacje = korelacje,
               scenariusze =  30000,
               ratingi_poczatkowe = c("A", "B", "CCC"),
               dataratings = data_ratings_df,
               data_stopy_zwrotu = stopy_zwrotu_df,
               data_stopy_odzysku = stopy_odzysku_df, 
               lata = c(3,5,2), 
               cena_wykupu = c(100000, 50000, 50000),
               kupony = c(0,5000,10000), 
               typ = c("Subordinated", "Senior Secured", "Senior Unsecured"), 
               kwantyl = 0.999,
               los=T)

VaRiESLOS <- data.frame("VaR"=c(var_bez_korelacji_los$VaR, var_z_korelacja_los$VaR), "ES"=c(var_bez_korelacji_los$ES, var_z_korelacja_los$ES), row.names = c("Bez korelacji", "Z korelacjami"))
VaR i ES z losowaniem stopy odzysku
datatable(VaRiESLOS)

Na podstawie otrzymanych wartości, można wyciągnąć wniosek, że wartości VaR i ES są zdecydowanie większe jeżeli losuję procentową wartość odzysku jeśli firma zbankrutuje.

Na podstawie dokumentacji technicznej CreditMetrics na przykładzie opisać, jakie są sposoby wyznaczania korelacji w modelu.

Pierwszą metodą szacowania korelacji jest bezpośrednie oszacowanie wspólnych ruchów jakości kredytowej. Polega ona na analizie szeregów czasowych ratingów kredytowych wielu firm. Przykładowo, badano 1 234 firmy z ocenami S&P senior unsecured, unikając szacowania korelacji i stosowania modeli opisowych. Metoda ta bada wszystkie możliwe pary firm (ponad 1,13 miliona kombinacji) i pozwala na nieparametryczną estymację prawdopodobieństw migracji jakości kredytowej, jednakże traktuje firmy o tym samym ratingu jako identyczne (np. dwa banki będą jednoznaczne z bankiem i rafinerią). Drugim sposobem szacowania korelacji jakości kredytowej za pomocą danych historycznych jest przeanalizowanie historii cen obligacji korporacyjnych. Takie podejście ma dwa wymagania: odpowiednie dane dotyczące historii cen obligacji oraz model łączący ceny obligacji z zdarzeniami kredytowymi. Tam, gdzie dostępne są dane dotyczące historii cen obligacji, możliwe jest oszacowanie pewnego rodzaju korelacji kredytowej, poprzez najpierw wyodrębnienie spreadów kredytowych z cen obligacji, a następnie oszacowanie korelacji w ruchach tych spreadów. Aby uzyskać parametry wymagane do CreditMetrics, konieczne jest przyjęcie modelu, który łączy ruchy spreadów ze zdarzeniami kredytowymi.